/*
 * Copyright(c) 2010 Philip Foulkes <philip.foulkes@gmail.com>
 *
 * This file is free software and is made available under the
 * terms of the GNU General Public License, version 2, or at your
 * option, any later version
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 */

#include <linux/errno.h>
#include <linux/slab.h>
#include <linux/hardirq.h>

#include "mrp_private.h"
#include "mrp_applicant.h"
#include "mrp_attribute.h"
#include "mrp_state_machine.h"

/**
*   Applicant state table
*/
static const int mrp_applicant_state_table [MRP_PROTO_EVENT_NUM] [MRP_APPLICANT_STATE_NUM] =
{
    [MRP_PROTO_EVENT_Begin]
        = { MRP_STATE_MACHINE_SET_UP_STATE_1(MRP_APPLICANT_STATE_NO_CHANGE),
            MRP_STATE_MACHINE_SET_UP_STATE_1(MRP_APPLICANT_STATE_VO),
            MRP_STATE_MACHINE_SET_UP_STATE_1(MRP_APPLICANT_STATE_VO),
            MRP_STATE_MACHINE_SET_UP_STATE_1(MRP_APPLICANT_STATE_VO),
            MRP_STATE_MACHINE_SET_UP_STATE_1(MRP_APPLICANT_STATE_VO),
            MRP_STATE_MACHINE_SET_UP_STATE_1(MRP_APPLICANT_STATE_VO),
            MRP_STATE_MACHINE_SET_UP_STATE_1(MRP_APPLICANT_STATE_VO),
            MRP_STATE_MACHINE_SET_UP_STATE_1(MRP_APPLICANT_STATE_VO),
            MRP_STATE_MACHINE_SET_UP_STATE_1(MRP_APPLICANT_STATE_VO),
            MRP_STATE_MACHINE_SET_UP_STATE_1(MRP_APPLICANT_STATE_VO),
            MRP_STATE_MACHINE_SET_UP_STATE_1(MRP_APPLICANT_STATE_VO),
            MRP_STATE_MACHINE_SET_UP_STATE_1(MRP_APPLICANT_STATE_VO) },
    [MRP_PROTO_EVENT_New]
        = { MRP_STATE_MACHINE_SET_UP_STATE_1(MRP_APPLICANT_STATE_VN),
            MRP_STATE_MACHINE_SET_UP_STATE_1(MRP_APPLICANT_STATE_VN),
            MRP_STATE_MACHINE_SET_UP_STATE_1(MRP_APPLICANT_STATE_NO_CHANGE),
            MRP_STATE_MACHINE_SET_UP_STATE_1(MRP_APPLICANT_STATE_NO_CHANGE),
            MRP_STATE_MACHINE_SET_UP_STATE_1(MRP_APPLICANT_STATE_VN),
            MRP_STATE_MACHINE_SET_UP_STATE_1(MRP_APPLICANT_STATE_VN),
            MRP_STATE_MACHINE_SET_UP_STATE_1(MRP_APPLICANT_STATE_VN),
            MRP_STATE_MACHINE_SET_UP_STATE_1(MRP_APPLICANT_STATE_VN),
            MRP_STATE_MACHINE_SET_UP_STATE_1(MRP_APPLICANT_STATE_VN),
            MRP_STATE_MACHINE_SET_UP_STATE_1(MRP_APPLICANT_STATE_VN),
            MRP_STATE_MACHINE_SET_UP_STATE_1(MRP_APPLICANT_STATE_VN),
            MRP_STATE_MACHINE_SET_UP_STATE_1(MRP_APPLICANT_STATE_VN) },
    [MRP_PROTO_EVENT_Join]
        = { MRP_STATE_MACHINE_SET_UP_STATE_1(MRP_APPLICANT_STATE_VP),
            MRP_STATE_MACHINE_SET_UP_STATE_1(MRP_APPLICANT_STATE_NO_CHANGE),
            MRP_STATE_MACHINE_SET_UP_STATE_1(MRP_APPLICANT_STATE_NO_CHANGE),
            MRP_STATE_MACHINE_SET_UP_STATE_1(MRP_APPLICANT_STATE_NO_CHANGE),
            MRP_STATE_MACHINE_SET_UP_STATE_1(MRP_APPLICANT_STATE_NO_CHANGE),
            MRP_STATE_MACHINE_SET_UP_STATE_1(MRP_APPLICANT_STATE_NO_CHANGE),
            MRP_STATE_MACHINE_SET_UP_STATE_1(MRP_APPLICANT_STATE_AA),
            MRP_STATE_MACHINE_SET_UP_STATE_1(MRP_APPLICANT_STATE_AP),
            MRP_STATE_MACHINE_SET_UP_STATE_1(MRP_APPLICANT_STATE_QP),
            MRP_STATE_MACHINE_SET_UP_STATE_1(MRP_APPLICANT_STATE_NO_CHANGE),
            MRP_STATE_MACHINE_SET_UP_STATE_1(MRP_APPLICANT_STATE_NO_CHANGE),
            MRP_STATE_MACHINE_SET_UP_STATE_1(MRP_APPLICANT_STATE_VP) },
    [MRP_PROTO_EVENT_Lv]
        = { MRP_STATE_MACHINE_SET_UP_STATE_1(MRP_APPLICANT_STATE_NO_CHANGE),
            MRP_STATE_MACHINE_SET_UP_STATE_1(MRP_APPLICANT_STATE_VO),
            MRP_STATE_MACHINE_SET_UP_STATE_1(MRP_APPLICANT_STATE_LA),
            MRP_STATE_MACHINE_SET_UP_STATE_1(MRP_APPLICANT_STATE_LA),
            MRP_STATE_MACHINE_SET_UP_STATE_1(MRP_APPLICANT_STATE_LA),
            MRP_STATE_MACHINE_SET_UP_STATE_1(MRP_APPLICANT_STATE_LA),
            MRP_STATE_MACHINE_SET_UP_STATE_1(MRP_APPLICANT_STATE_NO_CHANGE),
            MRP_STATE_MACHINE_SET_UP_STATE_1(MRP_APPLICANT_STATE_NO_CHANGE),
            MRP_STATE_MACHINE_SET_UP_STATE_1(MRP_APPLICANT_STATE_NO_CHANGE),
            MRP_STATE_MACHINE_SET_UP_STATE_1(MRP_APPLICANT_STATE_AO),
            MRP_STATE_MACHINE_SET_UP_STATE_1(MRP_APPLICANT_STATE_QO),
            MRP_STATE_MACHINE_SET_UP_STATE_1(MRP_APPLICANT_STATE_NO_CHANGE) },
    [MRP_PROTO_EVENT_rNew]
        = { MRP_STATE_MACHINE_SET_UP_STATE_1(MRP_APPLICANT_STATE_NO_CHANGE),
            MRP_STATE_MACHINE_SET_UP_STATE_1(MRP_APPLICANT_STATE_NO_CHANGE),
            MRP_STATE_MACHINE_SET_UP_STATE_1(MRP_APPLICANT_STATE_NO_CHANGE),
            MRP_STATE_MACHINE_SET_UP_STATE_1(MRP_APPLICANT_STATE_NO_CHANGE),
            MRP_STATE_MACHINE_SET_UP_STATE_1(MRP_APPLICANT_STATE_NO_CHANGE),
            MRP_STATE_MACHINE_SET_UP_STATE_1(MRP_APPLICANT_STATE_NO_CHANGE),
            MRP_STATE_MACHINE_SET_UP_STATE_1(MRP_APPLICANT_STATE_NO_CHANGE),
            MRP_STATE_MACHINE_SET_UP_STATE_1(MRP_APPLICANT_STATE_NO_CHANGE),
            MRP_STATE_MACHINE_SET_UP_STATE_1(MRP_APPLICANT_STATE_NO_CHANGE),
            MRP_STATE_MACHINE_SET_UP_STATE_1(MRP_APPLICANT_STATE_NO_CHANGE),
            MRP_STATE_MACHINE_SET_UP_STATE_1(MRP_APPLICANT_STATE_NO_CHANGE),
            MRP_STATE_MACHINE_SET_UP_STATE_1(MRP_APPLICANT_STATE_NO_CHANGE) },
    [MRP_PROTO_EVENT_rJoinIn]
        = { MRP_STATE_MACHINE_SET_UP_STATE_1(MRP_APPLICANT_STATE_AO),
            MRP_STATE_MACHINE_SET_UP_STATE_1(MRP_APPLICANT_STATE_AP),
            MRP_STATE_MACHINE_SET_UP_STATE_1(MRP_APPLICANT_STATE_NO_CHANGE),
            MRP_STATE_MACHINE_SET_UP_STATE_1(MRP_APPLICANT_STATE_NO_CHANGE),
            MRP_STATE_MACHINE_SET_UP_STATE_1(MRP_APPLICANT_STATE_QA),
            MRP_STATE_MACHINE_SET_UP_STATE_1(MRP_APPLICANT_STATE_NO_CHANGE),
            MRP_STATE_MACHINE_SET_UP_STATE_1(MRP_APPLICANT_STATE_NO_CHANGE),
            MRP_STATE_MACHINE_SET_UP_STATE_1(MRP_APPLICANT_STATE_QO),
            MRP_STATE_MACHINE_SET_UP_STATE_1(MRP_APPLICANT_STATE_NO_CHANGE),
            MRP_STATE_MACHINE_SET_UP_STATE_1(MRP_APPLICANT_STATE_QP),
            MRP_STATE_MACHINE_SET_UP_STATE_1(MRP_APPLICANT_STATE_NO_CHANGE),
            MRP_STATE_MACHINE_SET_UP_STATE_1(MRP_APPLICANT_STATE_NO_CHANGE) },
    [MRP_PROTO_EVENT_rIn]
        = { MRP_STATE_MACHINE_SET_UP_STATE_1(MRP_APPLICANT_STATE_NO_CHANGE),
            MRP_STATE_MACHINE_SET_UP_STATE_1(MRP_APPLICANT_STATE_NO_CHANGE),
            MRP_STATE_MACHINE_SET_UP_STATE_1(MRP_APPLICANT_STATE_NO_CHANGE),
            MRP_STATE_MACHINE_SET_UP_STATE_1(MRP_APPLICANT_STATE_NO_CHANGE),
            MRP_STATE_MACHINE_SET_UP_STATE_1(MRP_APPLICANT_STATE_QA),
            MRP_STATE_MACHINE_SET_UP_STATE_1(MRP_APPLICANT_STATE_NO_CHANGE),
            MRP_STATE_MACHINE_SET_UP_STATE_1(MRP_APPLICANT_STATE_NO_CHANGE),
            MRP_STATE_MACHINE_SET_UP_STATE_1(MRP_APPLICANT_STATE_NO_CHANGE),
            MRP_STATE_MACHINE_SET_UP_STATE_1(MRP_APPLICANT_STATE_NO_CHANGE),
            MRP_STATE_MACHINE_SET_UP_STATE_1(MRP_APPLICANT_STATE_NO_CHANGE),
            MRP_STATE_MACHINE_SET_UP_STATE_1(MRP_APPLICANT_STATE_NO_CHANGE),
            MRP_STATE_MACHINE_SET_UP_STATE_1(MRP_APPLICANT_STATE_NO_CHANGE) },
    [MRP_PROTO_EVENT_rJoinMt]
        = { MRP_STATE_MACHINE_SET_UP_STATE_1(MRP_APPLICANT_STATE_NO_CHANGE),
            MRP_STATE_MACHINE_SET_UP_STATE_1(MRP_APPLICANT_STATE_NO_CHANGE),
            MRP_STATE_MACHINE_SET_UP_STATE_1(MRP_APPLICANT_STATE_NO_CHANGE),
            MRP_STATE_MACHINE_SET_UP_STATE_1(MRP_APPLICANT_STATE_NO_CHANGE),
            MRP_STATE_MACHINE_SET_UP_STATE_1(MRP_APPLICANT_STATE_NO_CHANGE),
            MRP_STATE_MACHINE_SET_UP_STATE_1(MRP_APPLICANT_STATE_AA),
            MRP_STATE_MACHINE_SET_UP_STATE_1(MRP_APPLICANT_STATE_NO_CHANGE),
            MRP_STATE_MACHINE_SET_UP_STATE_1(MRP_APPLICANT_STATE_NO_CHANGE),
            MRP_STATE_MACHINE_SET_UP_STATE_1(MRP_APPLICANT_STATE_AO),
            MRP_STATE_MACHINE_SET_UP_STATE_1(MRP_APPLICANT_STATE_NO_CHANGE),
            MRP_STATE_MACHINE_SET_UP_STATE_1(MRP_APPLICANT_STATE_AP),
            MRP_STATE_MACHINE_SET_UP_STATE_1(MRP_APPLICANT_STATE_VO) },
    [MRP_PROTO_EVENT_rMt]
        = { MRP_STATE_MACHINE_SET_UP_STATE_1(MRP_APPLICANT_STATE_NO_CHANGE),
            MRP_STATE_MACHINE_SET_UP_STATE_1(MRP_APPLICANT_STATE_NO_CHANGE),
            MRP_STATE_MACHINE_SET_UP_STATE_1(MRP_APPLICANT_STATE_NO_CHANGE),
            MRP_STATE_MACHINE_SET_UP_STATE_1(MRP_APPLICANT_STATE_NO_CHANGE),
            MRP_STATE_MACHINE_SET_UP_STATE_1(MRP_APPLICANT_STATE_NO_CHANGE),
            MRP_STATE_MACHINE_SET_UP_STATE_1(MRP_APPLICANT_STATE_AA),
            MRP_STATE_MACHINE_SET_UP_STATE_1(MRP_APPLICANT_STATE_NO_CHANGE),
            MRP_STATE_MACHINE_SET_UP_STATE_1(MRP_APPLICANT_STATE_NO_CHANGE),
            MRP_STATE_MACHINE_SET_UP_STATE_1(MRP_APPLICANT_STATE_AO),
            MRP_STATE_MACHINE_SET_UP_STATE_1(MRP_APPLICANT_STATE_NO_CHANGE),
            MRP_STATE_MACHINE_SET_UP_STATE_1(MRP_APPLICANT_STATE_AP),
            MRP_STATE_MACHINE_SET_UP_STATE_1(MRP_APPLICANT_STATE_VO) },
    [MRP_PROTO_EVENT_rLv]
        = { MRP_STATE_MACHINE_SET_UP_STATE_1(MRP_APPLICANT_STATE_LO),
            MRP_STATE_MACHINE_SET_UP_STATE_1(MRP_APPLICANT_STATE_NO_CHANGE),
            MRP_STATE_MACHINE_SET_UP_STATE_1(MRP_APPLICANT_STATE_NO_CHANGE),
            MRP_STATE_MACHINE_SET_UP_STATE_1(MRP_APPLICANT_STATE_VN),
            MRP_STATE_MACHINE_SET_UP_STATE_1(MRP_APPLICANT_STATE_VP),
            MRP_STATE_MACHINE_SET_UP_STATE_1(MRP_APPLICANT_STATE_VP),
            MRP_STATE_MACHINE_SET_UP_STATE_1(MRP_APPLICANT_STATE_NO_CHANGE),
            MRP_STATE_MACHINE_SET_UP_STATE_1(MRP_APPLICANT_STATE_LO),
            MRP_STATE_MACHINE_SET_UP_STATE_1(MRP_APPLICANT_STATE_LO),
            MRP_STATE_MACHINE_SET_UP_STATE_1(MRP_APPLICANT_STATE_VP),
            MRP_STATE_MACHINE_SET_UP_STATE_1(MRP_APPLICANT_STATE_VP),
            MRP_STATE_MACHINE_SET_UP_STATE_1(MRP_APPLICANT_STATE_NO_CHANGE) },
    [MRP_PROTO_EVENT_rLA]
        = { MRP_STATE_MACHINE_SET_UP_STATE_1(MRP_APPLICANT_STATE_LO),
            MRP_STATE_MACHINE_SET_UP_STATE_1(MRP_APPLICANT_STATE_NO_CHANGE),
            MRP_STATE_MACHINE_SET_UP_STATE_1(MRP_APPLICANT_STATE_NO_CHANGE),
            MRP_STATE_MACHINE_SET_UP_STATE_1(MRP_APPLICANT_STATE_VN),
            MRP_STATE_MACHINE_SET_UP_STATE_1(MRP_APPLICANT_STATE_VP),
            MRP_STATE_MACHINE_SET_UP_STATE_1(MRP_APPLICANT_STATE_VP),
            MRP_STATE_MACHINE_SET_UP_STATE_1(MRP_APPLICANT_STATE_NO_CHANGE),
            MRP_STATE_MACHINE_SET_UP_STATE_1(MRP_APPLICANT_STATE_LO),
            MRP_STATE_MACHINE_SET_UP_STATE_1(MRP_APPLICANT_STATE_LO),
            MRP_STATE_MACHINE_SET_UP_STATE_1(MRP_APPLICANT_STATE_VP),
            MRP_STATE_MACHINE_SET_UP_STATE_1(MRP_APPLICANT_STATE_VP),
            MRP_STATE_MACHINE_SET_UP_STATE_1(MRP_APPLICANT_STATE_NO_CHANGE) },
    [MRP_PROTO_EVENT_ReDeclare]
        = { MRP_STATE_MACHINE_SET_UP_STATE_1(MRP_APPLICANT_STATE_LO),
            MRP_STATE_MACHINE_SET_UP_STATE_1(MRP_APPLICANT_STATE_NO_CHANGE),
            MRP_STATE_MACHINE_SET_UP_STATE_1(MRP_APPLICANT_STATE_NO_CHANGE),
            MRP_STATE_MACHINE_SET_UP_STATE_1(MRP_APPLICANT_STATE_VN),
            MRP_STATE_MACHINE_SET_UP_STATE_1(MRP_APPLICANT_STATE_VP),
            MRP_STATE_MACHINE_SET_UP_STATE_1(MRP_APPLICANT_STATE_VP),
            MRP_STATE_MACHINE_SET_UP_STATE_1(MRP_APPLICANT_STATE_NO_CHANGE),
            MRP_STATE_MACHINE_SET_UP_STATE_1(MRP_APPLICANT_STATE_LO),
            MRP_STATE_MACHINE_SET_UP_STATE_1(MRP_APPLICANT_STATE_LO),
            MRP_STATE_MACHINE_SET_UP_STATE_1(MRP_APPLICANT_STATE_VP),
            MRP_STATE_MACHINE_SET_UP_STATE_1(MRP_APPLICANT_STATE_VP),
            MRP_STATE_MACHINE_SET_UP_STATE_1(MRP_APPLICANT_STATE_NO_CHANGE) },
    [MRP_PROTO_EVENT_periodic]
        = { MRP_STATE_MACHINE_SET_UP_STATE_1(MRP_APPLICANT_STATE_NO_CHANGE),
            MRP_STATE_MACHINE_SET_UP_STATE_1(MRP_APPLICANT_STATE_NO_CHANGE),
            MRP_STATE_MACHINE_SET_UP_STATE_1(MRP_APPLICANT_STATE_NO_CHANGE),
            MRP_STATE_MACHINE_SET_UP_STATE_1(MRP_APPLICANT_STATE_NO_CHANGE),
            MRP_STATE_MACHINE_SET_UP_STATE_1(MRP_APPLICANT_STATE_NO_CHANGE),
            MRP_STATE_MACHINE_SET_UP_STATE_1(MRP_APPLICANT_STATE_AA),
            MRP_STATE_MACHINE_SET_UP_STATE_1(MRP_APPLICANT_STATE_NO_CHANGE),
            MRP_STATE_MACHINE_SET_UP_STATE_1(MRP_APPLICANT_STATE_NO_CHANGE),
            MRP_STATE_MACHINE_SET_UP_STATE_1(MRP_APPLICANT_STATE_NO_CHANGE),
            MRP_STATE_MACHINE_SET_UP_STATE_1(MRP_APPLICANT_STATE_NO_CHANGE),
            MRP_STATE_MACHINE_SET_UP_STATE_1(MRP_APPLICANT_STATE_AP),
            MRP_STATE_MACHINE_SET_UP_STATE_1(MRP_APPLICANT_STATE_NO_CHANGE) },
    [MRP_PROTO_EVENT_tx] =
        { MRP_STATE_MACHINE_SET_UP_STATE_2(MRP_APPLICANT_STATE_NO_CHANGE, MRP_PROTO_ACTION_ABsAB),
          MRP_STATE_MACHINE_SET_UP_STATE_2(MRP_APPLICANT_STATE_AA, MRP_PROTO_ACTION_sJ),
          MRP_STATE_MACHINE_SET_UP_STATE_2(MRP_APPLICANT_STATE_AN, MRP_PROTO_ACTION_sN),
          MRP_STATE_MACHINE_SET_UP_STATE_2(MRP_APPLICANT_STATE_QA, MRP_PROTO_ACTION_sN),
          MRP_STATE_MACHINE_SET_UP_STATE_2(MRP_APPLICANT_STATE_QA, MRP_PROTO_ACTION_sJ),
          MRP_STATE_MACHINE_SET_UP_STATE_2(MRP_APPLICANT_STATE_NO_CHANGE, MRP_PROTO_ACTION_ABsJAB),
          MRP_STATE_MACHINE_SET_UP_STATE_2(MRP_APPLICANT_STATE_VO, MRP_PROTO_ACTION_sL),
          MRP_STATE_MACHINE_SET_UP_STATE_2(MRP_APPLICANT_STATE_NO_CHANGE, MRP_PROTO_ACTION_ABsAB),
          MRP_STATE_MACHINE_SET_UP_STATE_2(MRP_APPLICANT_STATE_NO_CHANGE, MRP_PROTO_ACTION_ABsAB),
          MRP_STATE_MACHINE_SET_UP_STATE_2(MRP_APPLICANT_STATE_QA, MRP_PROTO_ACTION_sJ),
          MRP_STATE_MACHINE_SET_UP_STATE_2(MRP_APPLICANT_STATE_NO_CHANGE, MRP_PROTO_ACTION_ABsAB),
          MRP_STATE_MACHINE_SET_UP_STATE_2(MRP_APPLICANT_STATE_VO, MRP_PROTO_ACTION_s) },
    [MRP_PROTO_EVENT_txLA] =
        { MRP_STATE_MACHINE_SET_UP_STATE_2(MRP_APPLICANT_STATE_LO, MRP_PROTO_ACTION_ABsAB),
          MRP_STATE_MACHINE_SET_UP_STATE_2(MRP_APPLICANT_STATE_AA, MRP_PROTO_ACTION_s),
          MRP_STATE_MACHINE_SET_UP_STATE_2(MRP_APPLICANT_STATE_AN, MRP_PROTO_ACTION_sN),
          MRP_STATE_MACHINE_SET_UP_STATE_2(MRP_APPLICANT_STATE_QA, MRP_PROTO_ACTION_sN),
          MRP_STATE_MACHINE_SET_UP_STATE_2(MRP_APPLICANT_STATE_QA, MRP_PROTO_ACTION_sJ),
          MRP_STATE_MACHINE_SET_UP_STATE_2(MRP_APPLICANT_STATE_NO_CHANGE, MRP_PROTO_ACTION_sJ),
          MRP_STATE_MACHINE_SET_UP_STATE_2(MRP_APPLICANT_STATE_LO, MRP_PROTO_ACTION_ABsAB),
          MRP_STATE_MACHINE_SET_UP_STATE_2(MRP_APPLICANT_STATE_LO, MRP_PROTO_ACTION_ABsAB),
          MRP_STATE_MACHINE_SET_UP_STATE_2(MRP_APPLICANT_STATE_LO, MRP_PROTO_ACTION_ABsAB),
          MRP_STATE_MACHINE_SET_UP_STATE_2(MRP_APPLICANT_STATE_QA, MRP_PROTO_ACTION_sJ),
          MRP_STATE_MACHINE_SET_UP_STATE_2(MRP_APPLICANT_STATE_QA, MRP_PROTO_ACTION_sJ),
          MRP_STATE_MACHINE_SET_UP_STATE_2(MRP_APPLICANT_STATE_NO_CHANGE, MRP_PROTO_ACTION_ABsAB) },
    [MRP_PROTO_EVENT_txLAF]
        = { MRP_STATE_MACHINE_SET_UP_STATE_1(MRP_APPLICANT_STATE_LO),
            MRP_STATE_MACHINE_SET_UP_STATE_1(MRP_APPLICANT_STATE_VP),
            MRP_STATE_MACHINE_SET_UP_STATE_1(MRP_APPLICANT_STATE_VN),
            MRP_STATE_MACHINE_SET_UP_STATE_1(MRP_APPLICANT_STATE_VN),
            MRP_STATE_MACHINE_SET_UP_STATE_1(MRP_APPLICANT_STATE_VP),
            MRP_STATE_MACHINE_SET_UP_STATE_1(MRP_APPLICANT_STATE_VP),
            MRP_STATE_MACHINE_SET_UP_STATE_1(MRP_APPLICANT_STATE_LO),
            MRP_STATE_MACHINE_SET_UP_STATE_1(MRP_APPLICANT_STATE_LO),
            MRP_STATE_MACHINE_SET_UP_STATE_1(MRP_APPLICANT_STATE_LO),
            MRP_STATE_MACHINE_SET_UP_STATE_1(MRP_APPLICANT_STATE_VP),
            MRP_STATE_MACHINE_SET_UP_STATE_1(MRP_APPLICANT_STATE_VP),
            MRP_STATE_MACHINE_SET_UP_STATE_1(MRP_APPLICANT_STATE_NO_CHANGE) }
};

/**
*   Get the state based on the supplied event and state
*/
static int mrp_get_applicant_state(int mrp_protocol_event, int mrp_applicant_state, int * mrp_new_applicant_state)
{
    int res;

    if ((res = mrp_get_new_state(mrp_applicant_state_table, mrp_protocol_event, MRP_PROTO_EVENT_MIN, MRP_PROTO_EVENT_MAX, mrp_applicant_state,
            MRP_APPLICANT_STATE_MIN, MRP_APPLICANT_STATE_MAX, MRP_APPLICANT_STATE_NO_CHANGE)) >= 0)
    {
        *mrp_new_applicant_state = res;
        return 0;
    }

    return res;
}

/**
*   Get the protocol action based on the supplied event and state
*/
static int mrp_get_applicant_protocol_action1(int mrp_protocol_event, int mrp_applicant_state, int * mrp_protocol_action)
{
    int res;

    if ((res = mrp_get_new_protocol_action1(mrp_applicant_state_table, mrp_protocol_event, MRP_PROTO_EVENT_MIN, MRP_PROTO_EVENT_MAX, mrp_applicant_state, MRP_APPLICANT_STATE_MIN, MRP_APPLICANT_STATE_MAX)) >= 0)
    {
        *mrp_protocol_action = res;
        return 0;
    }

    return res;
}

/**
*   Get the protocol action based on the supplied event and state
*/
static int mrp_get_applicant_protocol_action2(int mrp_protocol_event, int mrp_applicant_state, int * mrp_protocol_action)
{
    int res;

    if ((res = mrp_get_new_protocol_action2(mrp_applicant_state_table, mrp_protocol_event, MRP_PROTO_EVENT_MIN, MRP_PROTO_EVENT_MAX, mrp_applicant_state, MRP_APPLICANT_STATE_MIN, MRP_APPLICANT_STATE_MAX)) >= 0)
    {
        *mrp_protocol_action = res;
        return 0;
    }

    return res;
}

static int mrp_applicant_state_changed(struct mrp_applicant * mrp_applicant, int old_state, int new_state)
{
    switch(new_state)
    {
        case MRP_APPLICANT_STATE_VP:
        case MRP_APPLICANT_STATE_VN:
        case MRP_APPLICANT_STATE_AN:
        case MRP_APPLICANT_STATE_AA:
        case MRP_APPLICANT_STATE_LA:
        case MRP_APPLICANT_STATE_AP:
        case MRP_APPLICANT_STATE_LO:
        {
            return mrp_attribute_request_transmit_opportunity(mrp_applicant->mrp_attribute, mrp_applicant);
        }

        case MRP_APPLICANT_STATE_VO:
        case MRP_APPLICANT_STATE_AO:
        case MRP_APPLICANT_STATE_QO:
        {
            // MRP_PRINT_INFO("CAN DELETE ATTRIBUTE IN THIS STATE\n");
            return 0;
        }
    }

    return 0;
}

static int mrp_applicant_perform_protocol_action(struct mrp_applicant * mrp_applicant, int protocol_action)
{
    switch(protocol_action)
    {
        case MRP_PROTO_ACTION_sN:	return mrp_attribute_perform_send_new(mrp_applicant->mrp_attribute);
        case MRP_PROTO_ACTION_sJ:	return mrp_attribute_perform_send_join(mrp_applicant->mrp_attribute);
        case MRP_PROTO_ACTION_sL:	return mrp_attribute_perform_send_leave(mrp_applicant->mrp_attribute);
        case MRP_PROTO_ACTION_s:	return mrp_attribute_perform_send(mrp_applicant->mrp_attribute);
        case MRP_PROTO_ACTION_ABsAB:
        {
            //MRP_PRINT_INFO("MRP_PROTO_ACTION_ABsAB\n");
            return 0;
        }
        case MRP_PROTO_ACTION_ABsLAB:
        {
            //MRP_PRINT_INFO("MRP_PROTO_ACTION_ABsLAB\n");
            return 0;
        }
        case MRP_PROTO_ACTION_ABsJAB:
        {
            //MRP_PRINT_INFO("MRP_PROTO_ACTION_ABsJAB\n");
            return 0;
        }
        default:
        {
            MRP_PRINT_INFO("%s %x\n", "UNSUPPORTED PROTO ACTION", protocol_action);
            return -EINVAL;
        }
    }
}

static struct mrp_state_machine_ops mrp_applicant_ops = {
    .mrp_state_machine_state_changed 			=(mrp_state_machine_state_changed) mrp_applicant_state_changed,
    .mrp_state_machine_perform_protocol_action 	=(mrp_state_machine_perform_protocol_action) mrp_applicant_perform_protocol_action,
    .mrp_state_machine_get_new_state 			= mrp_get_applicant_state,
    .mrp_state_machine_get_new_protocol_action1 = mrp_get_applicant_protocol_action1,
    .mrp_state_machine_get_new_protocol_action2 = mrp_get_applicant_protocol_action2,
};


// ======================================================================================================================================================================================
// ======================================================================================================================================================================================
struct mrp_applicant * mrp_applicant_create_and_init(struct mrp_attribute * mrp_attribute)
{
    struct mrp_applicant * mrp_a;

    if (   !(mrp_a = kzalloc(sizeof(struct mrp_applicant), MRP_GET_CONTEXT_ALLOC_FLAG))
        || mrp_state_machine_init(&mrp_a->mrp_state_machine, MRP_APPLICANT_STATE_VO, &mrp_applicant_ops, "mrp_applicant") )
    {
        mrp_applicant_destroy(&mrp_a);
        return NULL;
    }

    mrp_a->administrative_control = MRP_APPLICANT_ADMINISTRATIVE_CONTROL_NORMAL_PARTICIPANT;
    mrp_a->mrp_attribute = mrp_attribute;

    return mrp_a;
}

void mrp_applicant_destroy(struct mrp_applicant ** mrp_applicant)
{
    if (*mrp_applicant)
    {
        mrp_state_machine_clean_up(&((*mrp_applicant)->mrp_state_machine));
        kfree(*mrp_applicant);
        *mrp_applicant = NULL;
    }
}

int mrp_applicant_set_applicant_administrative_control(struct mrp_applicant * mrp_applicant, int applicant_administrative_control)
{
    if (applicant_administrative_control >= MRP_APPLICANT_ADMINISTRATIVE_CONTROL_MIN && applicant_administrative_control <= MRP_APPLICANT_ADMINISTRATIVE_CONTROL_MAX)
    {
        mrp_applicant->administrative_control = applicant_administrative_control;
        return 0;
    }

    return -EINVAL;
}
